package ec_si_template;

import java.util.Random;

import cec2010suite.Function;

/**
 * This class implements the individuals (i.e. particles, chromosomes, fish,
 * etc.)
 * 
 * @author Andreas Janecek
 * 
 */
public class Individual {

	/**
	 * the current location of the individual
	 */
	private double[] p;

	/**
	 * the current fitness of the individual
	 */
	private double fitness;

	/**
	 * the object of the function to be optimized
	 */
	private Function func;

	/**
	 * the index of the individual
	 */
	private int index;

	/**
	 * Constructor: Initialize the individual. Find random position within
	 * initialization range and compute fitness of this position
	 * 
	 * @param func
	 *            : the function object
	 * @param dim
	 *            : the problem dimension
	 * @param minInit
	 *            : lower limit of the initialization range
	 * @param maxInit
	 *            : upper limit of the initialization range
	 * @param minBound
	 *            : lower limit of the search space
	 * @param maxBound
	 *            : upper limit of the search space
	 */
	public Individual(int index, Function func, int dim, double minInit,
			double maxInit, double minBound, double maxBound) {
		this.index = index;
		this.func = func;
		this.p = new double[dim];

		// Initialize the swarm / the population at a new position
		for (int i = 0; i < dim; i++) {
			p[i] = (minInit + (new Random().nextDouble() * (maxInit - minInit)));
		}

		// calculate fitness
		this.fitness = this.func.compute(this.p);
	}

	/**
	 * return the current position
	 * 
	 * @return the current position
	 */
	public double[] getp() {
		return this.p;
	}

	/**
	 * return the current fitness
	 * 
	 * @return the current fitness
	 */
	public double getfitness() {
		return this.fitness;
	}

	/**
	 * return index
	 * 
	 * @return index
	 */
	public int getindex() {
		return this.index;
	}

	/**
	 * update the individual (this is algorithm specific) EXAMPLE: here, a
	 * simple random hill climber is used. If new fitness is better than the old
	 * one, p and fitness are updated
	 * 
	 * @param dim
	 *            : the problem dimension
	 * @param minBound
	 *            : lower limit of the search space
	 * @param maxBound
	 *            : upper limit of the search space
	 */
	public void update(int dim, double minBound, double maxBound) {

		// array for temporary positions
		double[] pTmp = new double[dim];

		Random rand = new Random();
		double prob = rand.nextInt(100);
				
		if (prob > 100 - Config.chanceOfMutation) {
			
			if(Config.mutation_function == Config.Mutation_type.UNIFORME){
				prob = rand.nextDouble();
			}else{
				prob = rand.nextGaussian();
			
			}
			
			// get new position for each dimension (limited to the search space)
			for (int j = 0; j < dim; j++) {
				pTmp[j] = this.p[j]	+ (minBound + (prob * (maxBound - minBound)));
			}

			
			// calculate fitness for pTmp
			double fitnessTmp = this.func.compute(pTmp);
			
			// if new fitness is better than the old one update individual
			if (fitnessTmp < this.fitness) {
				this.p = pTmp;
				this.fitness = fitnessTmp;
			}
		}

	}

}
